var fs 	      	= require('fs');
var WebSocket		= require('ws');
var selfSigned 	= require('openssl-self-signed-certificate');
//var options 		= { key: selfSigned.key , cert: selfSigned.cert }; 
var options = {
	key: fs.readFileSync('./cer/gyllr.com.key'),
	ca: [
    fs.readFileSync('./cer/GDCA TrustAUTH R5 ROOT.cer'),
    fs.readFileSync('./cer/GDCA TrustAUTH R4 DV SSL CA.cer')
    ],
	cert: fs.readFileSync('./cer/gyllr.com.cer')
};
var app   			= require('express')();
var express	 		= require('express');
var bodyParser  = require('body-parser');
var http  			= require('http').Server(app);
var https 			= require('https').Server(options,app);
var schedule    = require("node-schedule");

var log4js      = require('log4js');
log4js.configure({
  appenders: { 
    console: {
      type:"console"
    },
    dateFile: {
      type: "dateFile",
      filename: "logs/",
      pattern: "yyyy-MM-dd.log",
      alwaysIncludePattern: true,
      category: "dateFile"
    } 
  },
  categories: { default: { appenders: ['console','dateFile'], level: 'INFO' } }
});

const logger = log4js.getLogger('dateFile');

var users;
var lastpushs = [];
fs.readFile(__dirname + '/users.json',function(err,data){
    if(err) throw err;

    users = JSON.parse(data);
    if(!users) throw new Error('用户信息格式错误');
    //console.log(Array.prototype.forEach);
    //users.forEach(function(user){  
        //console.log(user.name);
    //});  
    
});

app.use(express.static(__dirname));
app.use(express.static(__dirname + '/assets'));
// see https://github.com/expressjs/body-parser
// 添加 body-parser 中间件就可以了
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

//express获取参数有三种方法：官网实例： 
   
//Checks route params (req.params), ex: /user/:id 
//Checks query string params (req.query), ex: ?id=12 
//Checks urlencoded body params (req.body), ex: id=

app.get('/', function(req, res) {
  res.send('This is a WebSocket Server! <br /> [http://] is disabled');
});
app.get('/app.apk', function(req, res) {
  res.setHeader('Content-Type','application/vnd.android.package-archive')
  res.sendfile(__dirname + '/app.apk');
});
app.get('/broadcast', function(req, res) {
  var msg = req.query.msg;
    if(!msg){
      // res.send(
      // '<form action=\"/broadcast\" method=\"get\">'
      // +'<input type=\"text\" name=\"msg\" id=\"msg\" />'
      // +'<input type=\"submit\" value=\"submit\" />'
      // +'</form>');
      // return;
      res.sendFile(__dirname + '/broadcast.html');
      return;
    }
  wss.broadcast(msg ? msg : 'empty message');
  res.send('Broadcast Complete!');
});
app.post('/broadcast',function(req,res){  
  var msg = req.body.msg;  
  //wss.broadcast(msg ? msg : 'empty message');
  wss.broadcastToGroup(msg ? msg : 'empty message');
  res.send("Broadcast Post Complete!");  
});
http.listen(80, function(){
	//console.log('HTTP listening on *:80');
});

https.listen(443, function(){
	//console.log('HTTPS listening on *:443');
});
 
//把创建好的https服务器丢进websocket的创建函数里，ws会用这个服务器来创建wss服务
//同样，如果丢进去的是个http服务的话那么创建出来的还是无加密的ws服务
var wss = new WebSocket.Server( { 
	server: http,
	verifyClient:function(info){
		//console.log(info.req.headers.imei);
    if(!info.req.headers.imei){ 
      //console.log('Rejected:'+info.req.connection.remoteAddress+' No IMEI');
      logger.info('Rejected:'+info.req.connection.remoteAddress+' No IMEI');
      return false;
    };
		//读取IMEI , 身份验证
		if (users.some(function(val){return val.imei == info.req.headers.imei;})){//99000828536605
			return true;
		}
		else {
      //console.log('Rejected:'+info.req.connection.remoteAddress+' IMEI:'+info.req.headers.imei);
      logger.info('Rejected:'+info.req.connection.remoteAddress+' IMEI:'+info.req.headers.imei);
			return false;
    }
	} 
});
//console.log('WebSocket Server listening on *:'+ (http == wss.options.server ? '80':'443'));
logger.info('▌▌Futures WebSocket Server Start listening on *:'+ (http == wss.options.server ? '80':'443'));

function heartbeat() {
  this.isAlive = true;
  console.log(this.user.name + ' PONG | connections:'+wss.clients.size);
}
function setUserInfo(user) {
  this.user=user;
  //console.log('set imei:'+imei);
}
// Broadcast to all.
wss.broadcast = function broadcast(data) {
  var log = 'broadcast:' + data + ' users:';
  wss.clients.forEach(function each(client) {
    if (client.readyState === WebSocket.OPEN) {
      client.send(data);
      log += ' '+client.user.name;
    }
  });
  logger.info(log);
};

// Broadcast to group.
wss.broadcastToGroup = function(data) {
  if(data.split('|').length < 3) return;
  //增加监控推送报文 {TEXT | XXXX | 2017-07-19 11:29:45 | 推送内容字符串}
  //● broadcastToGroup ● {OPEN | l1709 | 2017-07-19 11:29:45 | SELL | 9250#} users: qmx cr lr
  var log = '● broadcastToGroup ● {' + data + '} users:';
  var msgType = data.split('|')[0].trim().toLowerCase();
  var code = data.split('|')[1].trim().toLowerCase();
  var dt = data.split('|')[2].trim();
  if(msgType === 'text'){
	data = data.split('|')[3].trim();;
  }
  wss.clients.forEach(function(client) {
    if (client.readyState === WebSocket.OPEN) {
      if(client.user.group.some(function(val){ return code == val.trim().toLowerCase();})){
        client.send(data);
        log += ' '+client.user.name;
      }
    }
  });
  logger.info(log);
  var i = lastpushs.findIndex(function(element){ return code === element.code.trim().toLowerCase(); });
  //最后推送表里无此代码,创建
  if( i === -1) {
    lastpushs.push({code:code,data:data,datetime:Date.parse(dt)});
  } else {//有此代码,更新
    lastpushs[i].data = data;
    lastpushs[i].datetime = Date.parse(dt);
  }
};

wss.on( 'connection', function ( wsConnect , req) {
	//为client 设置身份信息
	setUserInfo.call(wsConnect,users.find(function(user){return user.imei == req.headers.imei;}));
  //console.log(wsConnect.user.name);
  //最后推送里包含此用户关注的代码
  if(lastpushs.some(function(val){ return val.code === wsConnect.user.group[0].trim().toLowerCase();})){
    var lastpush = lastpushs.find(function(val){ return val.code === wsConnect.user.group[0].trim().toLowerCase();}); 
    var now = new Date();
    var today = new Date(now.getFullYear(),now.getMonth(),now.getDate());
    if(lastpush.datetime >= today){
      try { wsConnect.send(lastpush.data); }
      catch (e) { logger.info(e.message); }
    }
  }

	//console.log( 'a user connected:'+ req.connection.remoteAddress + ' Name:' + wsConnect.user.name + ' IMEI:' + wsConnect.user.imei);
  //■ qmx connected    ■ IMEI:861206035088989 IP:::ffff:115.33.207.114
  logger.info( '■ '+wsConnect.user.name+' connected IMEI:' + wsConnect.user.imei + ' IP:' + req.connection.remoteAddress);
  wsConnect.on( 'message', function ( message ) {
      logger.info( message );
  try { wsConnect.send('Reply:'+ message); }
  catch (e) { logger.info(e.message); }
  });
	wsConnect.isAlive = true;
	wsConnect.on('pong', heartbeat);
	wsConnect.on('ping', function(){console.log(this.user.name + ' PING');});
	wsConnect.on('close', function(code){
		//console.log(this.user.name + ' connection closed,code:'+code);
    //□ qmx disconnected □ code:1006
    logger.info('□ '+this.user.name+' disconnected code:'+code);
	});
	wsConnect.on('error', function(error){
		//console.log(this.user.name + ' error:'+error.message);
    logger.info(this.user.name + ' error:'+error.message);
	});
});

const interval = setInterval(function ping() {
  wss.clients.forEach(function each(ws) {
	//console.log(ws);
    if (ws.isAlive === false) return ws.terminate();

    ws.isAlive = false;
    ws.ping('', false, true);
  });
}, 30*1000);
//30 * * * * *      每一分钟的30秒触发
//00 00 15 * * 1-5  周一到周五下午3点
// * * * * * *
// ┬ ┬ ┬ ┬ ┬ ┬
// │ │ │ │ │ |
// │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
// │ │ │ │ └───── month (1 - 12)
// │ │ │ └────────── day of month (1 - 31)
// │ │ └─────────────── hour (0 - 23)
// │ └──────────────────── minute (0 - 59)
// └───────────────────────── second (0 - 59, OPTIONAL)
var j = schedule.scheduleJob('00 00 15 * * 1-5', function(){
  //console.log("检查今日收盘有无推送:"+ new Date());
  logger.info("检查今日收盘有无推送:"+ new Date());
  var now = new Date();
  var today1459 = new Date(now.getFullYear(),now.getMonth(),now.getDate(),14,59,00);
  var today2100 = new Date(now.getFullYear(),now.getMonth(),now.getDate(),21,00,00);
  if(lastpushs.some(function(val) { return val.datetime >= today1459 && val.datetime < today2100 && val.code.trim().toLowerCase() !== 'monitor';})){
    return;
  }
  wss.broadcast('今日收盘无推送');
});